//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include "fm.h"


EXTERN void PoSetFMPowerOn(Boolean PowerOn);
#define DEFINE_FM_API(func_ptr_type, index) \
            ((func_ptr_type)g_FmApiForZener[index])

#include <zenr_api.h>

#define nu_FMInit                   zapi_FM->Init
#define nu_FMDeinit                 zapi_FM->Deinit
#define nu_FMOn                     zapi_FM->On
#define nu_FMOff                    zapi_FM->Off
#define nu_FMSetBand                zapi_FM->SetBand
#define nu_FMSetFrequency           zapi_FM->SetFrequency
#define nu_FMGetFrequency           zapi_FM->GetFrequency
#define nu_FMSetMoStMode            zapi_FM->SetMoStMode
#define nu_FMMute                   zapi_FM->Mute
#define nu_FMRfDependentMute        zapi_FM->RfDependentMute
#define nu_FMSetRDS                 zapi_FM->SetRDS
#define nu_FMSetAF                  zapi_FM->SetAF
#define nu_FMSeek                   zapi_FM->Seek
#define nu_FMSetVolume              zapi_FM->SetVolume
#define nu_FMSetRssiSeachLevel      zapi_FM->SetRssiSeachLevel
#define nu_FMGetProgramIndictor     zapi_FM->GetProgramIndictor
#define nu_FMSetRxAudioPath         zapi_FM->SetRxAudioPath


//PUBILC
#define FM_SEARCH_UP                0x01
#define FM_SEARCH_DOWN              0x02
#define FM_SET_CHANNEL_FREQ         0x03
#define FM_GET_CHANNEL_FREQ         0x04
#define FM_SET_VOLUME_RANGE_HI      0x05
#define FM_SET_VOLUME_RANGE_LO      0x06
#define FM_STOP                     0x09
#define FM_SELECT_PATH              0x0a
//PRIVATE
#define FM_SET_BAND                 0x0c
#define FM_SET_MOST_MODE            0x0d
#define FM_SET_RSSIS_SEACH_LEVEL    0x0e
#define FM_MUTE                     0x0f
#define FM_RF_DEPENDENT_MUTE        0x10
#define FM_SET_RDS                  0x11
#define FM_SET_AF                   0x12
#define FM_GET_PROGRAM_INDICTOR     0x13


ECode CFM::Init()
{
    ECode ec = NOERROR;
    if(nu_FMOn()){
        DRV_EXPRESSION(ERRORLEVEL, kprintf("FM_ON failed\n"));
        ec = E_FAIL;
        return ec;
    }

    if(nu_FMSetBand(0)){
        DRV_EXPRESSION(ERRORLEVEL, kprintf("FM_SET_BAND failed\n"));
        ec = E_FAIL;
        goto EXIT;
    }

    if(nu_FMSetRssiSeachLevel(0)){
        DRV_EXPRESSION(ERRORLEVEL, kprintf("FM_SET_RSSIS_SEACH_LEVEL failed\n"));
        ec = E_FAIL;
        goto EXIT;
    }

    if(nu_FMSetMoStMode(0)){
        DRV_EXPRESSION(ERRORLEVEL, kprintf("FM_SET_MOST_MODE failed\n"));
        ec = E_FAIL;
        goto EXIT;
    }

    return ec;

EXIT:
    nu_FMOff();
    return ec;

}


ECode CFM::Control(
    /* [in] */ Handle32 controlCode,
    /* [in] */ const MemoryBuf &inBuffer,
    /* [out] */ MemoryBuf* pOutBuffer,
    /* [out] */ IEvent** ppCompletionEvent)
{
    unsigned int iOutBuf = NULL;
    int iParam = 0;
    ECode ec = NOERROR;

    if(0 == m_iInit){
        ec = Init();
        if(FAILED(ec)){
            DRV_EXPRESSION(ERRORLEVEL, kprintf("FM_ON failed\n"));
            return ec;
        }
        PoSetFMPowerOn(TRUE);
        m_iInit = 1;
    }

    switch (controlCode) {

        case FM_STOP: {
            if(nu_FMOff()) {
                DRV_EXPRESSION(ERRORLEVEL, kprintf("FM_OFF failed\n"));
                ec = E_FAIL;
            }
            PoSetFMPowerOn(FALSE);
            m_iInit = 0;
            break;
        }

        case FM_SET_BAND: {
            if(NULL == inBuffer.GetPayload()){
                return E_INVALID_ARGUMENT;
            }
            iParam = *(int *)inBuffer.GetPayload();
            if(nu_FMSetBand(iParam)){
                DRV_EXPRESSION(ERRORLEVEL, kprintf("FM_SET_BAND failed\n"));
                ec = E_FAIL;
            }
            break;
        }
        case FM_SET_CHANNEL_FREQ: {
            if(NULL == inBuffer.GetPayload()){
                return E_INVALID_ARGUMENT;
            }
            iParam = *(int *)inBuffer.GetPayload();
            if(nu_FMSetFrequency((unsigned int)iParam)){
                DRV_EXPRESSION(ERRORLEVEL, kprintf("FM_SET_CHANNEL_FREQ failed\n"));
                ec = E_FAIL;
            }
            break;
        }
        case FM_GET_CHANNEL_FREQ: {
            if(NULL == pOutBuffer->GetPayload()){
                return E_INVALID_ARGUMENT;
            }
            if(nu_FMGetFrequency(&iOutBuf)){
                DRV_EXPRESSION(ERRORLEVEL, kprintf("FM_GET_CHANNEL_FREQ failed\n"));
                ec = E_FAIL;
            } else {
                pOutBuffer->Copy((Byte *)&iOutBuf, sizeof(unsigned int));
            }
            break;
        }

        case FM_SEARCH_UP:{
            if(NULL == pOutBuffer->GetPayload()){
                return E_INVALID_ARGUMENT;
            }
            if(nu_FMSeek(0)){
                DRV_EXPRESSION(ERRORLEVEL, kprintf("FM_SEARCH_UP failed\n"));
                ec = E_FAIL;
                break;
            }
            WaitResult wr;
            EventState state;
            m_SeekEvent.Wait(&wr, &state);
            if(nu_FMGetFrequency(&iOutBuf)){
                DRV_EXPRESSION(ERRORLEVEL, kprintf("FM_SEARCH_UP FM_GET_CHANNEL_FREQ failed\n"));
                ec = E_FAIL;
            } else {
                pOutBuffer->Copy((Byte *)&iOutBuf, sizeof(unsigned int));
            }

            break;
        }
        case FM_SEARCH_DOWN:{
            if(NULL == pOutBuffer->GetPayload()){
                return E_INVALID_ARGUMENT;
            }
            if(nu_FMSeek(1)){
                DRV_EXPRESSION(ERRORLEVEL, kprintf("FM_SEARCH_DOWN failed\n"));
                ec = E_FAIL;
                break;
            }
            WaitResult wr;
            EventState state;
            m_SeekEvent.Wait(&wr, &state);
            if(nu_FMGetFrequency(&iOutBuf)){
                DRV_EXPRESSION(ERRORLEVEL, kprintf("FM_SEARCH_DOWN FM_GET_CHANNEL_FREQ failed\n"));
                ec = E_FAIL;
            } else {
                pOutBuffer->Copy((Byte *)&iOutBuf, sizeof(unsigned int));
            }
            break;
        }
        case FM_SET_VOLUME_RANGE_LO:{
            break;
        }
        case FM_SET_VOLUME_RANGE_HI: {
            if(NULL == inBuffer.GetPayload()){
                return E_INVALID_ARGUMENT;
            }
            iParam = *(int *)inBuffer.GetPayload();
            if(nu_FMSetVolume(iParam)){
                DRV_EXPRESSION(ERRORLEVEL, kprintf("FM_SET_VOLUME failed\n"));
                ec = E_FAIL;
            }
            break;
        }
        case FM_SET_MOST_MODE: {
            if(NULL == inBuffer.GetPayload()){
                return E_INVALID_ARGUMENT;
            }
            iParam = *(int *)inBuffer.GetPayload();
            if(nu_FMSetMoStMode(iParam)){
                DRV_EXPRESSION(ERRORLEVEL, kprintf("FM_SET_MOST_MODE failed\n"));
                ec = E_FAIL;
            }
            break;
        }
        case FM_MUTE: {
            if(NULL == inBuffer.GetPayload()){
                return E_INVALID_ARGUMENT;
            }
            iParam = *(int *)inBuffer.GetPayload();
            if(nu_FMMute(iParam)){
                DRV_EXPRESSION(ERRORLEVEL, kprintf("nu_FMMute failed\n"));
                ec = E_FAIL;
            }
            break;
        }
        case FM_RF_DEPENDENT_MUTE: {
            if(NULL == inBuffer.GetPayload()){
                return E_INVALID_ARGUMENT;
            }
            iParam = *(int *)inBuffer.GetPayload();
            if(nu_FMRfDependentMute(iParam)){
                DRV_EXPRESSION(ERRORLEVEL, kprintf("nu_FMRfDependentMute failed\n"));
                ec = E_FAIL;
            }
            break;
        }
        case FM_SET_RDS: {
            if(NULL == inBuffer.GetPayload()){
                return E_INVALID_ARGUMENT;
            }
            iParam = *(int *)inBuffer.GetPayload();
            if(nu_FMSetRDS(iParam)){
                DRV_EXPRESSION(ERRORLEVEL, kprintf("FM_SET_RDS failed\n"));
                ec = E_FAIL;
            }
            break;
        }
        case FM_SET_AF: {
            if(NULL == inBuffer.GetPayload()){
                return E_INVALID_ARGUMENT;
            }
            iParam = *(int *)inBuffer.GetPayload();
            if(nu_FMSetAF(iParam)){
                DRV_EXPRESSION(ERRORLEVEL, kprintf("FM_SET_AF failed\n"));
                ec = E_FAIL;
            }
            break;
        }

        case FM_SET_RSSIS_SEACH_LEVEL: {
            if(NULL == inBuffer.GetPayload()){
                return E_INVALID_ARGUMENT;
            }
            iParam = *(int *)inBuffer.GetPayload();
            if(nu_FMSetRssiSeachLevel(iParam)){
                DRV_EXPRESSION(ERRORLEVEL, kprintf("FM_SET_RSSIS_SEACH_LEVEL failed\n"));
                ec = E_FAIL;
            }
            break;

        }
        case FM_GET_PROGRAM_INDICTOR: {
            if(NULL == pOutBuffer->GetPayload()){
                return E_INVALID_ARGUMENT;
            }
            if(nu_FMGetProgramIndictor(&iOutBuf)){
                DRV_EXPRESSION(ERRORLEVEL, kprintf("FM_GET_PROGRAM_INDICTOR failed\n"));
                ec = E_FAIL;
            } else {
                pOutBuffer->Copy((Byte *)&iOutBuf, sizeof(unsigned int));
            }
            break;
        }
        case FM_SELECT_PATH: {
            if(NULL == inBuffer.GetPayload()){
                return E_INVALID_ARGUMENT;
            }
            iParam = *(int *)inBuffer.GetPayload();
            if(nu_FMSetRxAudioPath(iParam)){
                DRV_EXPRESSION(ERRORLEVEL, kprintf("FM_SELECT_PATH failed\n"));
                ec = E_FAIL;
            }
            break;
        }
        default:{
            ec = E_NOT_IMPLEMENTED;
            break;
        }
    }

    return ec;
}

void CFM::Dispose()
{
    nu_FMDeinit();
}

EXTERN IDeviceDriver * CDECL CreateFM(uint_t uDeviceNo, void *pvParameter)
{
    CFM* fm = new CFM;
    if (!fm) {
        DRV_EXPRESSION(ERRORLEVEL, kprintf("Not enough memory\n"));

        return NULL;
    }

    fm->AddRef();

    if(nu_FMInit((Uint32)&fm->m_SeekEvent)){
        fm->Release();
        return NULL;
    }
    kprintf("CreateFM OK!\n");
    return (IDeviceDriver *)fm;
}

